package com.dituhui.tool.elastic;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import net.sf.json.JSONObject;

public class ElasticSearchUtil {
	private static final String DEFAULT_SEARCH_TYPE = "1";
	private String index;
	private String type;

	private ElasticSearchAPI api = new ElasticSearchAPI();

	/***
	 * ES的写入方法
	 * 
	 * @param datas 数据集map
	 * @param host ES服务地址
	 * @return 写入结果
	 */
	public String write(List<Map<String, Object>> datas, String host) {
		String routing = null;
		return write(datas, routing, host);
	}

	/***
	 * ES的写入方法
	 * 
	 * @param datas 数据集map
	 * @param routing ES routing，如果值是null，ES会默认使用id字段。
	 * @param host ES服务地址
	 * @return 写入结果
	 */
	public String write(List<Map<String, Object>> datas, String routing, String host) {
		// 构建json对象，便于es解析
		JSONObject jData = new JSONObject();

		jData.accumulate("index", this.getIndex());
		jData.accumulate("_type", this.getType());
		if (routing != null) {
			jData.accumulate("routing", routing);
		}
		jData.accumulate("datas", datas);

		return api.update(jData, host); // 调用更新
	}

	/***
	 * ES的读取方法
	 * 
	 * @param queryBean ElasticParameter
	 * @param host ES服务地址
	 * @return list中封装的为json字符串
	 */
	public List<String> read(ElasticParameter queryBean, String host) {
		String routing = null;
		return read(queryBean, routing, host);
	}

	/***
	 * ES的读取方法
	 * 
	 * @param queryBean ElasticParameter
	 * @param routing ES routing，如果值是null，ES会默认使用id字段。
	 * @param host ES服务地址
	 * @return list中封装的为json字符串
	 */
	public List<String> read(ElasticParameter queryBean, String routing, String host) {
		JSONObject jsonObject = JSONObject.fromObject(convert(queryBean));

		if (!jsonObject.containsKey("searchtype")) {
			jsonObject.accumulate("searchtype", DEFAULT_SEARCH_TYPE);
		}
		// 如果routing不为空并且jsonObject里没有routing时，就进行设置。
		if (routing != null && !jsonObject.containsKey("routing")) {
			jsonObject.accumulate("routing", routing);
		}

		SearchHit[] hits = api.search(jsonObject, host).getHits().getHits();

		List<String> list = new ArrayList<String>();
		for (SearchHit hit : hits) {
			// 5.2.x
			list.add(hit.getSourceAsString());
			// 2.2.0
			// if (queryBean.getReturnFields() == null || queryBean.getReturnFields().length == 0) {
			// // {"desc":"for testing","userKey":"00000000000000000000000000000000","version":"1.0.0"}
			// list.add(hit.getSourceAsString());
			// } else {
			// // 设置了查询字段
			// JSONObject resultJson = new JSONObject();
			// SearchHitField searchHitField = hit.field("admincode");
			// System.out.println("searchHitField=" + searchHitField);
			// System.out.println("hits[i].fields().size()=" + hit.fields().size());
			// System.out.println("hits[i].getFields().size()=" + hit.getFields().size());
			// System.out.println("hit.getSourceAsString()=" + hit.getSourceAsString());
			// for (String fieldName : hit.fields().keySet()) {
			// resultJson.accumulate(fieldName, hit.getFields().get(fieldName).getValue());
			// }
			// list.add(resultJson.toString());
			// break;
			// }
		}
		// System.out.println("hits.length = " + hits.length);

		return list;
	}

	/***
	 * ES的读取方法
	 * 
	 * @param queryBean ElasticParameter
	 * @param host ES服务地址
	 * @return list中封装的为json字符串
	 */
	public List<Map<String, Object>> readToMapList(ElasticParameter queryBean, String host) {
		String routing = null;
		return readToMapList(queryBean, routing, host);
	}

	/***
	 * ES的读取方法
	 * 
	 * @param queryBean ElasticParameter
	 * @param routing ES routing，如果值是null，ES会默认使用id字段。
	 * @param host ES服务地址
	 * @return list中封装的为json字符串
	 */
	public List<Map<String, Object>> readToMapList(ElasticParameter queryBean, String routing, String host) {
		JSONObject jsonObject = JSONObject.fromObject(convert(queryBean));

		if (!jsonObject.containsKey("searchtype")) {
			jsonObject.accumulate("searchtype", DEFAULT_SEARCH_TYPE);
		}
		// 如果routing不为空并且jsonObject里没有routing时，就进行设置。
		if (routing != null && !jsonObject.containsKey("routing")) {
			jsonObject.accumulate("routing", routing);
		}

		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

		SearchHits searchHits = api.search(jsonObject, host).getHits();
		for (SearchHit searchHit : searchHits) {
			Map<String, Object> map = new HashMap<String, Object>();

			map.put("_index", searchHit.getIndex());
			map.put("_type", searchHit.getType());
			map.put("_source", searchHit.getSource());

			list.add(map);
		}

		return list;
	}

	/***
	 * 删除索引
	 * 
	 * @param indexToDelete 索引
	 * @param host ES服务地址
	 */
	public void deleteIndex(String indexToDelete, String host) {
		api.deleteIndex(indexToDelete, host);
	}

	/***
	 * 将querybean转化为Map对象
	 * 
	 * @param querybean querybean
	 * @return Map对象
	 */
	protected Map<String, Object> convert(Object querybean) {
		Map<String, Object> returnMap = new HashMap<String, Object>();

		Class clazz = querybean.getClass(); // 获取类名

		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz);

			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

			for (int i = 0; i < propertyDescriptors.length; i++) {
				PropertyDescriptor descriptor = propertyDescriptors[i];
				String propertyName = descriptor.getName();

				if (!propertyName.equals("class")) {

					Method readMethod = descriptor.getReadMethod();

					Object result = readMethod.invoke(querybean, new Object[0]);

					if (result != null) { // 属性为null时，不加载至返回参数
						returnMap.put(propertyName, result);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return returnMap;
	}

	/**
	 * 获取索引
	 * 
	 * @return 索引
	 */
	public String getIndex() {
		return this.index;
	}

	/***
	 * 设置写入的索引名称
	 * 
	 * @param index 索引
	 */
	public void setIndex(String index) {
		this.index = index;
	}

	/**
	 * 获取Type
	 * 
	 * @return Type
	 */
	public String getType() {
		return this.type;
	}

	/***
	 * 设置写入数据的type属性值
	 * 
	 * @param type Type
	 */
	public void setType(String type) {
		this.type = type;
	}

}
